package com.bolt.admin.security.shiro.filter;

import com.bolt.admin.security.shiro.AuthContextHolder;
import com.bolt.admin.security.shiro.DefaultAuthUserDetails;
import com.bolt.admin.security.shiro.session.OnlineSession;
import com.bolt.admin.security.shiro.session.OnlineSessionDAO;
import com.bolt.common.utils.StrUtil;
import com.bolt.common.web.RequestUtil;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by Administrator on 2020/9/21.
 */
public class OnlineSessionFilter extends AccessControlFilter {

    public static final String ONLINE_SESSION = "online_session";
    /**
     * 强制退出后重定向的地址
     */
    private String loginUrl;


    private OnlineSessionDAO onlineSessionDAO;

    private boolean ajaxMessage(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        if (RequestUtil.isAjaxRequest(httpServletRequest)) {
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            //追加loginUrl到响应头，方便AJAX转向登录界面
            String loginUrl = getLoginUrl();
            if (loginUrl.startsWith("/")) {
                loginUrl = httpServletRequest.getContextPath() + loginUrl;
            }
            httpServletResponse.addHeader(HttpHeaders.LOCATION, loginUrl);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false；
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        Subject subject = getSubject(request, response);
        if (subject == null || subject.getSession() == null) {
            ajaxMessage(request, response);
            return false;
        }
        Session session = onlineSessionDAO.readSession(subject.getSession().getId());
        if (session != null && session instanceof OnlineSession) {
            OnlineSession onlineSession = (OnlineSession) session;
            request.setAttribute(ONLINE_SESSION, onlineSession);
            // 把user对象设置进去
            boolean isGuest = StrUtil.isEmpty(onlineSession.getUserId());
            if (isGuest) {
                DefaultAuthUserDetails authUser = (DefaultAuthUserDetails) AuthContextHolder.getAuthUserDetails();
                if (null != authUser) {
                    onlineSession.setUserId(authUser.getUserDTO().getId());
                    onlineSession.setUserName(authUser.getUserDTO().getUserName());
                    onlineSession.setOrgName(authUser.getUserDTO().getOrgName());
                    onlineSession.setNickName(authUser.getUserDTO().getRealName());
                    onlineSession.setKey((String) subject.getSession().getId());
                    onlineSessionDAO.update(onlineSession);
                } else {
                    return ajaxMessage(request, response);
                }
            }
        }
        return true;
    }

    /**
     * 表示当访问拒绝时是否已经处理了；如果返回true表示需要继续处理；如果返回false表示该拦截器实例已经处理了，将直接返回即可。
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (subject != null) {
            subject.logout();
        }
        saveRequestAndRedirectToLogin(request, response);
        return false;
    }

    // 跳转到登录页
    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        WebUtils.issueRedirect(request, response, loginUrl);
    }

    @Override
    public String getLoginUrl() {
        return loginUrl;
    }

    @Override
    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    public OnlineSessionDAO getOnlineSessionDAO() {
        return onlineSessionDAO;
    }

    public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) {
        this.onlineSessionDAO = onlineSessionDAO;
    }
}

 